package com.whfc.fmam.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.JSONUtil;
import com.whfc.common.util.PageUtil;
import com.whfc.fmam.dao.FmamPlanCheckLogMapper;
import com.whfc.fmam.dao.FmamPlanMapper;
import com.whfc.fmam.dao.FmamPlanMatMapper;
import com.whfc.fmam.entity.bo.FmamPlan;
import com.whfc.fmam.entity.bo.FmamPlanCheckLog;
import com.whfc.fmam.entity.bo.FmamPlanMat;
import com.whfc.fmam.entity.dto.FmamPlanCheckLogDTO;
import com.whfc.fmam.entity.dto.FmamPlanDTO;
import com.whfc.fmam.entity.dto.FmamPlanListCountDTO;
import com.whfc.fmam.entity.dto.FmamPlanMatDTO;
import com.whfc.fmam.entity.enums.MatPlanCheckState;
import com.whfc.fmam.entity.enums.MatPlanOptionResult;
import com.whfc.fmam.entity.enums.MatPlanOptionType;
import com.whfc.fmam.entity.qo.FmamPlanAddQO;
import com.whfc.fmam.entity.qo.FmamPlanCheckQO;
import com.whfc.fmam.entity.qo.FmamPlanEditQO;
import com.whfc.fmam.entity.qo.FmamPlanMatQO;
import com.whfc.fmam.service.FmamPlanService;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author LK
 * @description 材料服务
 */
@DubboService(interfaceClass = FmamPlanService.class, version = "1.0.0")
public class FmamPlanServiceImpl implements FmamPlanService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private FmamPlanMapper fmamPlanMapper;

    @Autowired
    private FmamPlanCheckLogMapper fmamPlanCheckLogMapper;

    @Autowired
    private FmamPlanMatMapper fmamPlanMatMapper;

    @Override
    public PageData<FmamPlanDTO> list(Integer userId, Integer deptId, Integer pageNum, Integer pageSize, List<Integer> states, Date startDate, Date endDate) throws BizException {
        logger.info("获取材料计划列表,userId:{}, deptId:{}, pageNum:{}, pageSize:{}, states:{}, startDate:{}, endDate:{}", userId, deptId, pageNum, pageSize, states, startDate, endDate);
        if (endDate != null) {
            endDate = DateUtil.getDateEnd(endDate);
        }
        if (states == null || states.size() <= 0) {
            return PageUtil.emptyPage();
        }
        PageHelper.startPage(pageNum, pageSize);
        List<FmamPlanDTO> list = fmamPlanMapper.selectPlanList(userId, deptId, states, startDate, endDate);
        PageHelper.clearPage();
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public Integer planListCount(Integer userId, Integer deptId, List<Integer> states, Date startDate, Date endDate) throws BizException {
        logger.info("获取材料计划列表统计,userId:{}, deptId:{}, states:{}, startDate:{}, endDate:{}", userId, deptId, states, startDate, endDate);
        return fmamPlanMapper.countPlanList(userId, deptId, states, startDate, endDate);
    }


    @Override
    public FmamPlanListCountDTO planListCount(Integer userId, Integer deptId, Date startDate, Date endDate) throws BizException {
        logger.info("获取材料计划列表统计,userId:{}, deptId:{}, startDate:{}, endDate:{}", userId, deptId, startDate, endDate);
        FmamPlanListCountDTO data = fmamPlanMapper.selectNumByDeptId(deptId, startDate, endDate);
        Integer submitCount = fmamPlanMapper.countPlanList(userId, deptId, null, startDate, endDate);
        data.setSubmitCount(submitCount);
        return data;
    }

    @Override
    public FmamPlanDTO detail(Integer planId) throws BizException {
        logger.info("查询材料计划详情,planId:{}", planId);
        FmamPlanDTO fmamPlanDTO = fmamPlanMapper.selectByPlanId(planId);
        if (fmamPlanDTO != null) {
            //补全材料信息
            List<FmamPlanMatDTO> fmamPlanMatList = fmamPlanMatMapper.selectByPlanId(planId);
            fmamPlanDTO.setMatList(fmamPlanMatList);
            //补全审批信息
            List<FmamPlanCheckLogDTO> fmamPlanCheckLogList = fmamPlanCheckLogMapper.selectByPlanId(planId);
            fmamPlanDTO.setCheckLogList(fmamPlanCheckLogList);
            fmamPlanDTO.setIsOpt(false);
        }
        return fmamPlanDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(FmamPlanAddQO param) throws BizException {
        logger.info("提交材料计划申请,FmamPlanAddQO:{}", param.toString());

        //查询编号或名称是否与数据中重复
        FmamPlanDTO planN = fmamPlanMapper.selectByPlanName(param.getName());
        if (planN != null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "材料计划名称已存在");
        }

        //新增材料计划
        FmamPlan fmamPlan = new FmamPlan();
        fmamPlan.setDeptId(param.getDeptId());
        fmamPlan.setDeptName(param.getDeptName());
        fmamPlan.setName(param.getName());
        fmamPlan.setCode(param.getCode());
        fmamPlan.setFileUrl(param.getFileUrl());
        fmamPlan.setPlanTime(new Date());
        fmamPlan.setUserId(param.getUserId());
        fmamPlan.setUserName(param.getUserName());
        fmamPlan.setState(MatPlanCheckState.TO_BE_CHECK.getValue());

        //插入计划表
        fmamPlanMapper.insertSelective(fmamPlan);
        Integer planId = fmamPlan.getId();

        //插入材料表
        savePlanMat(planId, param.getMatList());

        //增加操作日志
        this.addCheckLog(planId, MatPlanOptionType.REPORT, param.getUserId(), param.getUserName(), MatPlanOptionResult.QUALIFIED.getValue(), "制单");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(FmamPlanEditQO param) throws BizException {
        logger.info("重新编辑材料计划申请,FmamPlanAddQO:{}", param.toString());
        Integer planId = param.getPlanId();
        FmamPlan fmamPlan = fmamPlanMapper.selectByPrimaryKey(planId);
        //只有当材料申请计划被驳回,为审批不合格状态，才可以编辑
        if (fmamPlan != null && fmamPlan.getState().equals(MatPlanCheckState.UNQUALIFIED_CHECK.getValue())) {

            //查询编号或名称是否与数据中重复
            FmamPlanDTO planN = fmamPlanMapper.selectByPlanName(param.getName());
            if (planN != null && !planN.getPlanId().equals(planId)) {
                throw new BizException(ResultEnum.FAILURE.getCode(), "材料计划名称已存在");
            }

            Date date = new Date();
            fmamPlan.setName(param.getName());
            fmamPlan.setCode(param.getCode());
            fmamPlan.setFileUrl(param.getFileUrl());
            fmamPlan.setPlanTime(date);
            fmamPlan.setUpdateTime(date);
            fmamPlan.setUserId(param.getUserId());
            fmamPlan.setUserName(param.getUserName());
            //状态为待审批
            fmamPlan.setState(MatPlanCheckState.TO_BE_CHECK.getValue());

            //更新计划表，获取主键ID
            fmamPlanMapper.updateByPrimaryKey(fmamPlan);

            //删除材料表中原来的所有材料
            fmamPlanMatMapper.logicDelectMatByPlanId(planId);

            //重新插入编辑的新材料到材料表，获取主键ID
            savePlanMat(planId, param.getMatList());

            //增加操作日志
            this.addCheckLog(planId, MatPlanOptionType.REPORT, param.getUserId(), param.getUserName(), MatPlanOptionResult.QUALIFIED.getValue(), "重新制单");


        } else {
            throw new BizException(ResultEnum.FAILURE.getCode(), "材料计划审批中，不能编辑");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void del(Integer planId) throws BizException {
        logger.info("删除材料计划,planId:{}", planId);
        fmamPlanMapper.deleteLogicById(planId);
    }

    @Deprecated
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkPlan(FmamPlanCheckQO param) throws BizException {
        logger.info("审批材料计划流程,FmamPlanCheckQO:{}", param.toString());
        Integer planId = param.getPlanId();

        FmamPlan fmamPlan = fmamPlanMapper.selectByPrimaryKey(planId);

        FmamPlanCheckLog fmamPlanCheckLog = new FmamPlanCheckLog();
        //补全信息
        fmamPlanCheckLog.setPlanId(planId);
        fmamPlanCheckLog.setOpUserId(param.getOpUserId());
        fmamPlanCheckLog.setOpUserName(param.getOpUserName());
        fmamPlanCheckLog.setOpDesc(param.getOpDesc());
        fmamPlanCheckLog.setOpTime(new Date());
        fmamPlanCheckLog.setOpType(param.getOpType());

        //判断审批是否合格
        Integer opResult = param.getOpResult();
        if (opResult.equals(MatPlanOptionResult.QUALIFIED.getValue())) {
            //审批合格, 修改审批计划流程的信息
            fmamPlanCheckLog.setOpResult(MatPlanOptionResult.QUALIFIED.getValue());
            //更新计划信息
            Integer opType = param.getOpType();
            fmamPlanCheckLog.setOpType(opType);
            if (opType.equals(MatPlanOptionType.CHECK.getValue()) && fmamPlan.getState().equals(MatPlanCheckState.TO_BE_CHECK.getValue())) {
                //一审审批通过，修改计划的状态为 待复审
                fmamPlan.setState(MatPlanCheckState.TO_BE_REVIEWED.getValue());
            } else if (opType.equals(MatPlanOptionType.REVIEW.getValue()) && fmamPlan.getState().equals(MatPlanCheckState.TO_BE_REVIEWED.getValue())) {
                //二审复审通过，修改计划的状态为 待核验
                fmamPlan.setState(MatPlanCheckState.TO_BE_VERIFY.getValue());
            } else if (opType.equals(MatPlanOptionType.VERIFY.getValue()) && fmamPlan.getState().equals(MatPlanCheckState.TO_BE_VERIFY.getValue())) {
                //三审核验通过，修改计划的状态为 已完成
                fmamPlan.setState(MatPlanCheckState.SUCCESS.getValue());
            } else {
                //审批流程出错
                throw new BizException(ResultEnum.FAILURE.getCode(), "审批流程错误");
            }

        } else if (opResult.equals(MatPlanOptionResult.UNQUALIFIED.getValue())) {
            // 审批不合格
            fmamPlanCheckLog.setOpResult(MatPlanOptionResult.UNQUALIFIED.getValue());
            fmamPlan.setState(MatPlanCheckState.UNQUALIFIED_CHECK.getValue());
        } else {
            //审批流程出错
            throw new BizException(ResultEnum.FAILURE.getCode(), "审批错误");
        }

        //更新数据库材料计划表
        fmamPlanMapper.updateByPrimaryKeySelective(fmamPlan);

        //新增数据库材料审批流程记录
        fmamPlanCheckLogMapper.insertSelective(fmamPlanCheckLog);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void check1(FmamPlanCheckQO param) throws BizException {
        logger.info("材料计划审批(一审),FmamPlanCheckQO:{}", param.toString());
        Integer planId = param.getPlanId();
        Integer opResult = param.getOpResult();
        String opDesc = param.getOpDesc();
        Integer opUserId = param.getOpUserId();
        String opUserName = param.getOpUserName();

        //审批后计划状态
        MatPlanCheckState checkState = MatPlanOptionResult.QUALIFIED.getValue().equals(opResult) ? MatPlanCheckState.TO_BE_REVIEWED : MatPlanCheckState.UNQUALIFIED_CHECK;

        updatePlanMatState(param.getMatList());

        //增加操作日志
        this.addCheckLog(planId, MatPlanOptionType.CHECK, opUserId, opUserName, opResult, opDesc);

        //更新计划状态
        this.updatePlanState(planId, checkState);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void check2(FmamPlanCheckQO param) throws BizException {
        logger.info("材料计划复审(二审),FmamPlanCheckQO:{}", param.toString());
        Integer planId = param.getPlanId();
        Integer opResult = param.getOpResult();
        String opDesc = param.getOpDesc();
        Integer opUserId = param.getOpUserId();
        String opUserName = param.getOpUserName();

        //复审后计划状态
        MatPlanCheckState checkState = MatPlanOptionResult.QUALIFIED.getValue().equals(opResult) ? MatPlanCheckState.TO_BE_VERIFY : MatPlanCheckState.UNQUALIFIED_CHECK;

        updatePlanMatState(param.getMatList());

        //增加操作日志
        this.addCheckLog(planId, MatPlanOptionType.REVIEW, opUserId, opUserName, opResult, opDesc);

        //更新计划状态
        this.updatePlanState(planId, checkState);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void check3(FmamPlanCheckQO param) throws BizException {
        logger.info("材料计划核验(三审),FmamPlanCheckQO:{}", param.toString());
        Integer planId = param.getPlanId();
        Integer opResult = param.getOpResult();
        String opDesc = param.getOpDesc();
        Integer opUserId = param.getOpUserId();
        String opUserName = param.getOpUserName();

        //核验后计划状态
        MatPlanCheckState checkState = MatPlanOptionResult.QUALIFIED.getValue().equals(opResult) ? MatPlanCheckState.SUCCESS : MatPlanCheckState.UNQUALIFIED_CHECK;

        updatePlanMatState(param.getMatList());

        //增加操作日志
        this.addCheckLog(planId, MatPlanOptionType.VERIFY, opUserId, opUserName, opResult, opDesc);

        //更新计划状态
        this.updatePlanState(planId, checkState);
    }

    /**
     * 保存材料计划的材料
     *
     * @param planId  计划ID
     * @param matList 材料列表
     */
    private void savePlanMat(Integer planId, List<FmamPlanMatQO> matList) {
        if (matList != null && matList.size() > 0) {
            List<FmamPlanMat> list = new ArrayList<>();
            for (FmamPlanMatQO planMatQo : matList) {
                FmamPlanMat fmamPlanMat = new FmamPlanMat();
                BeanUtils.copyProperties(planMatQo, fmamPlanMat);
                fmamPlanMat.setPlanId(planId);
                list.add(fmamPlanMat);
            }
            //批量插入材料
            fmamPlanMatMapper.batchInsert(list);
        }
    }

    /**
     * 增加操作日志
     *
     * @param planId
     * @param optionType
     * @param opUserId
     * @param opUserName
     * @param opResult
     * @param opDesc
     */
    private void addCheckLog(Integer planId, MatPlanOptionType optionType, Integer opUserId, String opUserName, Integer opResult, String opDesc) {
        FmamPlanCheckLog fmamPlanCheckLog = new FmamPlanCheckLog();
        fmamPlanCheckLog.setPlanId(planId);
        fmamPlanCheckLog.setOpType(optionType.getValue());
        fmamPlanCheckLog.setOpTime(new Date());
        fmamPlanCheckLog.setOpUserId(opUserId);
        fmamPlanCheckLog.setOpUserName(opUserName);
        fmamPlanCheckLog.setOpResult(opResult);
        fmamPlanCheckLog.setOpDesc(opDesc);
        List<FmamPlanMatDTO> list = fmamPlanMatMapper.selectByPlanId(planId);
        if (!list.isEmpty()) {
            fmamPlanCheckLog.setPlanHistory(JSONUtil.toString(list));
        }
        fmamPlanCheckLogMapper.insertSelective(fmamPlanCheckLog);
    }

    /**
     * 更新材料计划状态
     *
     * @param planId
     * @param checkState
     */
    private void updatePlanState(Integer planId, MatPlanCheckState checkState) {
        FmamPlan fmamPlan = fmamPlanMapper.selectByPrimaryKey(planId);
        fmamPlan.setState(checkState.getValue());
        fmamPlanMapper.updateByPrimaryKeySelective(fmamPlan);
    }

    private void updatePlanMatState(List<FmamPlanMatQO> matList) {
        for (FmamPlanMatQO mat : matList) {
            fmamPlanMatMapper.updateStateByMatId(mat.getId(), mat.getCheckState());
        }
    }
}
